package com.acme.bankapp.service.bank;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.regex.Pattern;

import com.acme.bankapp.domain.bank.Account;
import com.acme.bankapp.domain.bank.Bank;
import com.acme.bankapp.domain.bank.Client;
import com.acme.bankapp.domain.bank.exception.AccountAlreadyAssignedException;
import com.acme.bankapp.domain.bank.exception.ClientExistsException;
import com.acme.bankapp.service.bank.builder.AccountBuilder;
import com.acme.bankapp.service.bank.builder.BuildingFailedException;
import com.acme.bankapp.service.bank.builder.ClientBuilder;
import com.acme.bankapp.service.bank.exception.ClientLineParseException;
import com.acme.bankapp.service.bank.exception.InvalidFeedFormatException;

public class BankDataLoaderService {
	private static final String TOKEN_DELIM = ";";
	private static final String PARAM_DELIM_REGEX = "=";

	public static Bank parseFile(File feedFile) throws IOException,
			InvalidFeedFormatException {
		Bank bank = new Bank();
		parseFile(feedFile, bank);
		return bank;
	}

	public static void parseFile(File feedFile, Bank bank) throws IOException,
			InvalidFeedFormatException {
		try (BufferedReader reader = new BufferedReader(
				new FileReader(feedFile))) {
			String line;
			while ((line = reader.readLine()) != null) {
				parseAndApplyClientLine(line, bank);
			}
		} catch (ClientLineParseException ex) {
			throw new InvalidFeedFormatException(feedFile);
		}
	}

	/**
	 * Parses client data from list and adds client to bank.
	 * 
	 * @param line
	 *            parsed line
	 * @param bank
	 *            bank instance
	 * @throws ClientLineParseException
	 */
	public static void parseAndApplyClientLine(String line, Bank bank)
			throws ClientLineParseException {
		StringTokenizer tokenizer = new StringTokenizer(line, TOKEN_DELIM);
		Map<String, String> properties = new HashMap<>();
		while (tokenizer.hasMoreTokens()) {
			Pattern pattern = Pattern.compile(PARAM_DELIM_REGEX);
			String[] parts = pattern.split(tokenizer.nextToken());
			if (parts.length != 2) {
				throw new ClientLineParseException();
			}
			String leftPart = parts[0];
			String rightPart = parts[1];
			properties.put(leftPart, rightPart);
		}
		addAccountToBank(bank, properties);
	}

	private static void addAccountToBank(Bank bank,
			Map<String, String> properties) throws ClientLineParseException {
		try {
			ClientBuilder clientBuilder = new ClientBuilder();
			Client client = clientBuilder.buildFromProperties(properties);
			AccountBuilder accountBuilder = new AccountBuilder();
			Account account = accountBuilder.buildFromProperties(properties);
			try {
				bank.addClient(client);
			} catch (ClientExistsException ex) {
				client = bank.locateClient(client);
			}
			client.addAccount(account);
		} catch (AccountAlreadyAssignedException | BuildingFailedException e) {
			throw new ClientLineParseException();
		}
	}
}